home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Windows News 2010 Summer - Disc 1
/
WN_Ete2010_CD1.iso
/
Onglet5
/
Weezo
/
Weezo setup.exe
/
{code_appDir}
/
www
/
local
/
UPnPMapping.php
< prev
next >
Wrap
PHP Script
|
2010-05-19
|
16KB
|
433 lines
<?php
/**
* UPnP NAT script
*
*
* PHP version 5
*
* LICENSE: This source file is subject to version 3.0 of the PHP license
* that is available through the world-wide-web at the following URI:
* http://www.php.net/license/3_0.txt. If you did not receive a copy of
* the PHP License and are unable to obtain it through the web, please
* send a note to license@php.net so we can mail you a copy immediately.
*
* @category NA
* @package NA
* @author Nicolas Bruley / Peer 2 World <contact@weezo.net>
* @copyright 2005-2008 Nicolas Bruley / Peer 2 World
* @license http://www.php.net/license/3_0.txt PHP License 3.0
* @version CVS: $Id:$
* @link http://www.weezo.net
* @since File available since Release 1.1.2
*/
/**
* @desc UPnP device
*
*/
class UPnPDevice{
private $serviceType;
private $SCPDURL;
private $controlURL;
private $friendlyName;
function __construct($serviceType, $SCPDURL, $controlURL, $friendlyName){
$this->serviceType=$serviceType;
$this->SCPDURL=$SCPDURL;
$this->controlURL=$controlURL;
$this->friendlyName=$friendlyName;
}
function debug($out=false){
cfAppendTextToFile('Device name : '.$this->friendlyName);
cfAppendTextToFile('Service type : '.$this->serviceType);
cfAppendTextToFile('SCPD URL : '.$this->SCPDURL);
cfAppendTextToFile('Control URL : '.$this->SCPDURL);
}
/**
* @desc Create a new port mapping
*
* @param integer $port : port number
* @param string $protocol : protocol ("UDP" or "TCP")
* @param string $description : Friendly name of port mapping
* @return boolean : true if success, false if failed
*/
function addPortMapping($port, $protocol, $lanIP, $description){
if(!is_numeric($port) || $port>65536 || $port<1 || ($protocol!='TCP' && $protocol!='UDP' && $protocol!='both')) {
trigger_error('Invalid port number or protocol', E_WARNING);
return false;
}
// TCP and UDP port mapping
if($protocol=='both')
return $this->addPortMapping($port,'TCP',$lanIP,$description) && $this->addPortMapping($port,'UDP',$lanIP,$description);
/*
$msg ="<NewRemoteHost></NewRemoteHost>\n";
$msg.="<NewExternalPort>".$port."</NewExternalPort>\n";
$msg.="<NewProtocol>".$protocol."</NewProtocol>\n";
$msg.="<NewInternalPort>".$port."</NewInternalPort>\n";
$msg.="<NewInternalClient>".$lanIP."</NewInternalClient>\n";
$msg.="<NewEnabled>1</NewEnabled>\n";
$msg.="<NewPortMappingDescription>".$description."</NewPortMappingDescription>\n";
$msg.="<NewLeaseDuration>0</NewLeaseDuration>\n";
*/
// Single protocol port mapping
$msg ="<NewRemoteHost xmlns:dt=\"urn:schemas-microsoft-com:datatypes\" dt:dt=\"string\"></NewRemoteHost>\n";
$msg.="<NewExternalPort xmlns:dt=\"urn:schemas-microsoft-com:datatypes\" dt:dt=\"ui2\">".$port."</NewExternalPort>\n";
$msg.="<NewProtocol xmlns:dt=\"urn:schemas-microsoft-com:datatypes\" dt:dt=\"string\">".$protocol."</NewProtocol>\n";
$msg.="<NewInternalPort xmlns:dt=\"urn:schemas-microsoft-com:datatypes\" dt:dt=\"ui2\">".$port."</NewInternalPort>\n";
$msg.="<NewInternalClient xmlns:dt=\"urn:schemas-microsoft-com:datatypes\" dt:dt=\"string\">".$lanIP."</NewInternalClient>\n";
$msg.="<NewEnabled xmlns:dt=\"urn:schemas-microsoft-com:datatypes\" dt:dt=\"boolean\">1</NewEnabled>\n";
$msg.="<NewPortMappingDescription xmlns:dt=\"urn:schemas-microsoft-com:datatypes\" dt:dt=\"string\">".$description."</NewPortMappingDescription>\n";
$msg.="<NewLeaseDuration xmlns:dt=\"urn:schemas-microsoft-com:datatypes\" dt:dt=\"ui4\">0</NewLeaseDuration>\n";
return $this->postAction('AddPortMapping', $msg);
}
/**
* @desc Delete mapped port
*
* @param integer $port : port number
* @param string $protocol : protocol ("UDP" or "TCP")
* @return boolean : true if success, false if failed
*/
function deletePortMapping($port, $protocol){
if(!is_numeric($port) || $port>65536 || $port<1 || ($protocol!='TCP' && $protocol!='UDP' && $protocol!='both')) {
trigger_error('Invalid port number or protocol', E_WARNING);
return false;
}
// TCP and UDP port mapping deletion
if($protocol=='both') return $this->deletePortMapping($port,'TCP') && $this->deletePortMapping($port,'UDP');
// Single protocol port mapping deletion
$msg ="<NewRemoteHost xmlns:dt=\"urn:schemas-microsoft-com:datatypes\" dt:dt=\"string\"></NewRemoteHost>\n";
$msg.="<NewExternalPort xmlns:dt=\"urn:schemas-microsoft-com:datatypes\" dt:dt=\"ui2\">".$port."</NewExternalPort>\n";
$msg.="<NewProtocol xmlns:dt=\"urn:schemas-microsoft-com:datatypes\" dt:dt=\"string\">".$protocol."</NewProtocol>\n";
return $this->postAction('DeletePortMapping', $msg);
}
/**
* @desc return external IP adress
*
* @return unknown
*/
function getExternalIPAddress(){
if(!$body=$this->postAction('GetExternalIPAddress', '')) return false;
$xml=new DOMDocument();
if(!@$xml->loadXML($body)) return false;
}
/**
* @desc send a POST request to device
*
* @param string $action : action (AddPortMapping, DeletePortMapping)
* @param string $msg : POST body
* @return boolean result
*/
function postAction($action, $msg){
$cnx=parse_url($this->controlURL);
// SOAP message
$message ='<?xml version="1.0"?>'."\r\n";
//$message.='<s:Envelope xmlns:s="http://schemas.xmlsoap.org/soap/envelope/" s:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/">'."\n";
//$message.="<s:Body>\n<u:".$action." xmlns:u=\"".$this->serviceType."\">\n";
$message='<SOAP-ENV:Envelope xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/" SOAP-ENV:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/">'."\n";
$message.="<SOAP-ENV:Body>\n<m:".$action." xmlns:m=\"".$this->serviceType."\">\n";
$message.=$msg;
//$message.="</u:".$action.">\n";
//$message.="</s:Body>\n</s:Envelope>";
$message.="</m:".$action.">\n";
$message.="</SOAP-ENV:Body>\n</SOAP-ENV:Envelope>\n";
$header ="POST ".$cnx['path'].((isset($cnx['query']))?'?'.$cnx['query']:'')." HTTP/1.1\r\n";
$header.="HOST: ".$cnx['host'].':'.$cnx['port']."\r\n";
$header.="CONTENT-TYPE: text/xml; charset=\"utf-8\"\r\n";
$header.="CONTENT-LENGTH: ".strlen($message)."\r\n";
$header.='SOAPACTION: "'.$this->serviceType.'#'.$action.'"'."\r\n";
$header.="\r\n";
//cfVarDump($header.$message);
// Open socket
if(!($handle = @fsockopen((($cnx['scheme']=='https')?'ssl://':'').$cnx['host'],$cnx['port'],$errno,$errstr))) return false;
// POST message
fwrite($handle, $header.$message);
// Get response
$response='';
/*while(!feof($handle))*/ $response.= fread($handle, 2048);
fclose($handle);
if(!cfParseHTTPResponse($response,$statusCode,$body,$headers)) {
//cfVarDump('Modem response error');
//cfVarDump(str_replace('<','<',$response));
return false;
}
// Method Not Allowed
if($statusCode==405){
// Rebuild MAN header
$header ="M-POST ".$cnx['path'].((isset($cnx['query']))?'?'.$cnx['query']:'')." HTTP/1.1\r\n";
$header.="HOST: ".$cnx['host'].':'.$cnx['port']."\r\n";
$header.="CONTENT-TYPE: text/xml; charset=\"utf-8\"\r\n";
$header.="CONTENT-LENGTH: ".strlen($message)."\r\n";
$header.="MAN: \"http://schemas.xmlsoap.org/soap/envelope/\"; ns=01\r\n";
$header.='01-SOAPACTION: "'.$this->serviceType.'#'.$action.'"'."\r\n";
$header.="\r\n";
// Open socket
if(!($handle = @fsockopen((($cnx['scheme']=='https')?'ssl://':'').$cnx['host'],$cnx['port'],$errno,$errstr))) return false;
// POST message
fwrite($handle, $header.$message);
// Get response
$response='';
/*while(!feof($handle))*/ $response.= fread($handle, 2048);
fclose($handle);
if(!cfParseHTTPResponse($response,$statusCode,$body,$headers)) return false;
}
if($statusCode!=200) {
//echo "<b>ERROR</b>";
//cfVarDump(str_replace('<','<',$response));
return false;
}
//echo "<b>Success</b>";
//cfVarDump(str_replace('<','<',$response));
return true;
}
}
/**
* @desc Get device from XML descriptor URL
*
* @param string $location : XML descriptor URL
* @return mixed UPnPDevice if ok, false if failed
*/
function UPnPGetDevice($location){
$url=parse_url($location);
if(!isset($url['host'])) return false;
// Send request to $location URL to retreive XML devices descriptor
if(!$xml=cfSocketHTTPRequest($location,3)) return false;
// Load XML
$dom=new DOMDocument();
$dom->loadXML($xml);
// URLBase
if($dom->getElementsByTagName('URLBase')->length) $URLBase=($dom->getElementsByTagName('URLBase')->item(0)->nodeValue); else $URLBase=false;
// Device name
if($dom->getElementsByTagName('friendlyName')->length) $friendlyName=($dom->getElementsByTagName('friendlyName')->item(0)->nodeValue); else $friendlyName=false;
// Browse service (s) for WANIPConnection or WANPPPConnection
for($i=0;$i<$dom->getElementsByTagName('service')->length;$i++){
$node=$dom->getElementsByTagName('service')->item($i);
if(!$node->getElementsByTagName('serviceType')->length) continue;
$serviceType=strtolower($node->getElementsByTagName('serviceType')->item(0)->nodeValue);
// Get service type
if($serviceType!='urn:schemas-upnp-org:service:wanipconnection:1' && $serviceType!='urn:schemas-upnp-org:service:wanpppconnection:1') continue;
$serviceType=($node->getElementsByTagName('serviceType')->item(0)->nodeValue);
// SCPDURL
if(!$node->getElementsByTagName('SCPDURL')->length) continue; else $SCPDURL=($node->getElementsByTagName('SCPDURL')->item(0)->nodeValue);
// controlURL
if(!$node->getElementsByTagName('controlURL')->length) continue; else $controlURL=($node->getElementsByTagName('controlURL')->item(0)->nodeValue);
break;
}
if(!isset($controlURL)) return false;
// transform path into full URL
if(!$URLBase) $URLBase=((isset($url['scheme'])?$url['scheme']:'http')).'://'.$url['host'].':'.((isset($url['port'])?$url['port']:'80')).'/';
if(substr($URLBase,-1)!='/') $URLBase.='/';
if(strtolower(substr($controlURL,0,4))!='http') $controlURL=$URLBase.(($controlURL[0]=='/')?substr($controlURL,1):$controlURL);
if(strtolower(substr($SCPDURL,0,4))!='http') $SCPDURL=$URLBase.(($SCPDURL[0]=='/')?substr($SCPDURL,1):$SCPDURL);
return new UPnPDevice($serviceType, $SCPDURL, $controlURL, $friendlyName);
}
/**
* @desc parse UDP IGD discover response
*
* @param string $SSDPResponse
* @return string : descriptor location if found, null if LOCATION: not found
*/
function UPnPDeviceLocation($SSDPResponse){
if(!$SSDPResponse) return null;
$lines=explode("\n",str_replace("\r","\n",str_replace("\n\n","\n",$SSDPResponse)));
if(count($lines)<3) return null;
$resp=explode(' ',$lines[0]);
// Check HTTP 200 OK
if(count($resp)!=3 || $resp[1]!=200 || strtoupper($resp[2])!='OK') return null;
// Search for LOCATION:
foreach ($lines as $line){
$line=trim($line);
if(substr(strtolower($line),0,9)=='location:') return trim(substr($line,9));
}
return null;
}
/**
* @desc Send UDP message to discover UPnP Internet Gateway Device
*
* @param integer $timeout : timeout for receiving message
* @return string : IGD descriptor URL if found or null if not found
*/
function UPnPFindDevice($timeout=3){
$mcast_addr='239.255.255.250'; $mcast_port=1900;
$mcast_msg ="M-SEARCH * HTTP/1.1\r\n";
$mcast_msg.="Host:239.255.255.250:1900\r\n";
//$mcast_msg.="ST:urn:schemas-UPnP-org:device:WANConnectionDevice:1\r\n"; // Whireshark
//$mcast_msg.="ST:UPnP:rootdevice\r\n"; // zbowling.com
$mcast_msg.="ST:urn:schemas-UPnP-org:device:InternetGatewayDevice:1\r\n"; // Python
$mcast_msg.="Man:\"ssdp:discover\"\r\n";
$mcast_msg.="MX:3\r\n";
$mcast_msg.="\r\n";
$mcast_2ndMessageDelay=0.5;
$secondMessageSent=false;
$sock=socket_create(AF_INET,SOCK_DGRAM,SOL_UDP);
socket_sendto($sock, $mcast_msg, strlen($mcast_msg), false, $mcast_addr, $mcast_port);
$location=null;
socket_set_nonblock($sock);
$i=0;
while($i<$timeout*100){ // the first non-full packet is the last.
$buffer='';
// Send the message a 2nd time
if(!$secondMessageSent && $i>$mcast_2ndMessageDelay*100) {
socket_sendto($sock, $mcast_msg, strlen($mcast_msg), false, $mcast_addr, $mcast_port);
$secondMessageSent=true;
}
// Receive data
@socket_recvfrom($sock, $buffer, 516, 0, $addr, $port);
//cfDbg($buffer,1);
if($location=UPnPDeviceLocation($buffer)) {
socket_close($sock);
return $location;
}
usleep(10000);
$i++;
}
socket_close($sock);
}
/*
***************************************************************************************************************************
* Process GET commands
***************************************************************************************************************************
*/
if(isset($_GET['action'])){
ignore_user_abort(true);
if(true || !cfMIssetVar('weezoUPnPDevice')){
if(!$location=UPnPFindDevice(3)) die('nok no UPnP devices found');
if(!($device=UPnPGetDevice($location))) die('nok error reading device location');
//cfMSetVar('weezoUPnPDevice',$device);
}
else $device=cfMGetVar('weezoUPnPDevice');
//$device->debug(1);
/**
* New port mapping
*/
if($_GET['action']=='addPortMapping'){
if(!isset($_GET['port']) || !isset($_GET['protocol']) || !isset($_GET['description']) || !isset($_GET['lanIP'])) die('nok incorrect parameters');
// Multiple ports mapping
if(is_array($_GET['port'])){
if(!is_array($_GET['protocol']) || !is_array($_GET['description']) || count($_GET['protocol'])!=count($_GET['port']) || count($_GET['description'])!=count($_GET['port'])) die('nok incorrect parameters');
$nb=0;
foreach ($_GET['port'] as $key=>$port) {
if($device->addPortMapping($port, $_GET['protocol'][$key],$_GET['lanIP'],$_GET['description'][$key])) $nb++;
}
if($nb==count($_GET['port'])) die('ok'); else die('nok '.$nb.' port(s) mapped');
}
// Single port mapping
else{
if($device->addPortMapping($_GET['port'],$_GET['protocol'],$_GET['lanIP'],$_GET['description'])) die('ok'); else die('nok port mapping unsuccessfull');
}
}
/**
* Delete port mapping
*/
elseif($_GET['action']=='deletePortMapping'){
if(!isset($_GET['port']) || !isset($_GET['protocol'])) die('nok incorrect parameters');
// Multiple ports deletion
if(is_array($_GET['port'])){
if(!is_array($_GET['protocol']) || count($_GET['protocol'])!=count($_GET['port'])) die('nok incorrect parameters');
$nb=0;
foreach ($_GET['port'] as $key=>$port) {
if($device->deletePortMapping($port, $_GET['protocol'][$key])) $nb++;
}
if($nb>0) die('ok'); else die('nok');
}
// Single port mapping deletion
else{
if($device->deletePortMapping($_GET['port'],$_GET['protocol'])) die('ok'); else die('nok port mapping deletion unsuccessfull');
}
}
/**
* Get external IP adress
*/
elseif($_GET['action']=='getExternalIPAddress'){
$device->getExternalIPAddress();
}
}
/**
* Test form
*/
exit;
?>
<form method="GET" name="UPnPForm">
<input type="hidden" name="action">
<input type="hidden" name="protocol" value="TCP">
<input type="hidden" name="description" value="WeezoTest83">
IP LAN <input type="text" name="lanIP" value="192.168.0.2" size="10"><br>
Port (TCP) <input type="text" name="port" value="80" size="3"><br>
<input type="button" value="Ouvrir" onclick="document.forms.UPnPForm.action.value='addPortMapping';document.forms.UPnPForm.submit()">
<input type="button" value="Fermer" onclick="document.forms.UPnPForm.action.value='deletePortMapping';document.forms.UPnPForm.submit()">
<input type="button" value="Adresse IP externe" onclick="document.forms.UPnPForm.action.value='getExternalIPAddress';document.forms.UPnPForm.submit()">
</form>
<pre>
<?php
system('ipconfig');
?></pre>